package edu.gmu.projects.fireresponder.xml.alerts;

import java.io.StringWriter;
import java.util.Iterator;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.cap12.cap.alertType;
import com.cap12.cap.cap122;
import com.cap12.cap.categoryType;
import com.cap12.cap.infoType;
import com.edxm10.EDXLDistributionType;
import com.edxm10.contentObjectType;

import edu.gmu.projects.fireresponder.FirstResponder;
import edu.gmu.projects.fireresponder.environment.Building;
import edu.gmu.projects.fireresponder.environment.Location;

public class AlertFactory {

	public static Alert createAlertFromMessage(String msg) {
		Document doc = null;
		try {
			doc = com.altova.xml.XmlTreeOperations.loadXml(msg);
			return createAlertFromDocument(doc);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Alert createAlertFromDocument(Document doc) {
		Alert alert = null;
		
		alert = createFirstResponderAlert(doc);
		if(alert != null) {
			return  alert;		
		}
		alert = createCapAlert(doc);
		if(alert != null) {
			return  alert;		
		}
		
		return alert;
	}
	
	public static CapAlert createCapAlert(Document doc) {
		try {
			cap122 cap = new cap122(doc);

			// not a cap alert
			alertType alert = cap.alert.first();
			if(alert.getNode() == null) {
				return null;
			}

			infoType info = alert.info.first();
			
			CapAlert capAlert = null;
			if(info.getNode() == null) {
				capAlert = new CapAlert();
			} else if(info.category.first().getEnumerationValue() == categoryType.EFIRE &&
					info.event.first().getValue().equals(SmokeAlarmAlert.EVENT)) {
				capAlert = new SmokeAlarmAlert();
			} else if(info.category.first().getEnumerationValue() == categoryType.ERESCUE &&
					info.event.first().getValue().equals(ResponderLocationAlert.EVENT)) {
				capAlert = new ResponderLocationAlert();
			} else if(info.category.first().getEnumerationValue() == categoryType.EOTHER &&
					info.event.first().getValue().equals(MotionDetectorAlert.EVENT)) {
				capAlert = new MotionDetectorAlert();
			} else if(info.category.first().getEnumerationValue() == categoryType.ESAFETY &&
					info.event.first().getValue().equals(BuildingDroppedAlert.EVENT)) {
				capAlert = new BuildingDroppedAlert();
			} else if(info.category.first().getEnumerationValue() == categoryType.ESAFETY &&
					info.event.first().getValue().equals(BuildingClearedAlert.EVENT)) {
				capAlert = new BuildingClearedAlert();
			} else if(info.category.first().getEnumerationValue() == categoryType.ESAFETY &&
					info.event.first().getValue().equals(BuildingAddedAlert.EVENT)) {
				capAlert = new BuildingAddedAlert();
			} else {
				capAlert = new CapAlert();				
			}
			
			capAlert.setId(alert.identifier.first().getValue());
			capAlert.setSender(alert.sender.first().getValue());
			capAlert.setTime(alert.sent.first().getValue().getValue());
			capAlert.setStatus(alert.status.first().getEnumerationValue());
			capAlert.setMessageType(alert.msgType.first().getEnumerationValue());
			capAlert.setSource(alert.source.first().getValue());
			capAlert.setScope(alert.scope.first().getEnumerationValue());

			capAlert.setCategory(info.category.first().getEnumerationValue());
			capAlert.setEvent(info.event.first().getValue());
			capAlert.setUrgency(info.urgency.first().getEnumerationValue());
			capAlert.setSeverity(info.severity.first().getEnumerationValue());
			capAlert.setCertainty(info.certainty.first().getEnumerationValue());
			capAlert.setLocation(new Location(info.area.first().areaDesc.first().getValue()));

			return capAlert;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static FirstResponderAlert createFirstResponderAlert(Document doc) {
		try {
			com.edxm10.edxm102 edxl = new com.edxm10.edxm102(doc);
			EDXLDistributionType alert = edxl.EDXLDistribution.first();

			// not a first responder alert
			try {
				if(alert.senderID.first().getNode() == null) {
					return null;
				}
			} catch (Exception e) {
				return null;
			}
			
			FirstResponderAlert firstResponderAlert = new FirstResponderAlert();
			
			firstResponderAlert.setResponder(findResponder(alert.senderID.first().getValue()));
			firstResponderAlert.setTime(alert.dateTimeSent.first().getValue().getValue());
			firstResponderAlert.setLocation(new Location(alert.targetArea.first().circle.first().getValue()));
			firstResponderAlert.setId(alert.distributionID.first().getValue());
			
			for(Iterator<?> itr = alert.contentObject.iterator(); itr.hasNext(); ) {
				contentObjectType contentObj = (contentObjectType) itr.next();
				if(contentObj.contentDescription.first().getValue().equals("Message")) {
					firstResponderAlert.setMessage(new String(contentObj.nonXMLContent.first().contentData.first().getValue()));
				} else if(contentObj.contentDescription.first().getValue().equals("Image")) {
					firstResponderAlert.setImageContents(contentObj.nonXMLContent.first().contentData.first().getValue());
					firstResponderAlert.setImageMimeType(contentObj.nonXMLContent.first().mimeType.first().getValue());
				} else if(contentObj.contentDescription.first().getValue().equals("Alert")) {
					Node embedded = contentObj.xmlContent.first().embeddedXMLContent.first().getNode();
					NodeList children  = embedded.getChildNodes();
					for(int i = 0; i < children.getLength(); i++) {
						Node n = children.item(i);
						if(n instanceof Element) {
							Alert embeddedAlert = createAlertFromMessage(nodeToString(n));
							if(embeddedAlert != null) {
								firstResponderAlert.addEmbeddedAlerts(embeddedAlert);								
							}
						}
					}
				}
			}
			return firstResponderAlert;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private static String nodeToString(Node node) { 
		return nodeToString(node, false);
	}
	
	private static String nodeToString(Node node, boolean xmlDecl) { 
		StringWriter sw = new StringWriter(); 
		try {   
			Transformer t = TransformerFactory.newInstance().newTransformer();   
			t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, xmlDecl ? "yes" : "no");   
			t.transform(new DOMSource(node), new StreamResult(sw)); 
		} catch (TransformerException te) {   
		} 
		return sw.toString();
	}

	/* Place holder functions
	 */
	public static FirstResponder findResponder(String id) {
		return new FirstResponder(id);
	}

	public static Building findBuilding(String id) {
		//return new Building(id);
		return new Building();
	}
	
}
